home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fifty: Elektronik
/
FIFTY Elektronik (PS_Computer_Vertrieb).iso
/
ps8
/
fty1031
/
comdemo.c
next >
Wrap
C/C++ Source or Header
|
1993-04-09
|
27KB
|
1,141 lines
/*
// COMDEMO.C
//
// Serial communications demo program for the Cport communications library.
//
// Copyright (c) 1993 Bri Productions
//
*/
#include "cport.h"
#include "xmodem.h"
#include <conio.h>
#include <stdlib.h>
#include <dos.h>
#include <bios.h>
#include <ctype.h>
#include <stdio.h>
/*
//-------------------------------------
//
// Microsoft portability
//
//-------------------------------------
*/
#if M_I86
#include <stdarg.h>
#include <time.h>
#include <graph.h>
#define BLUE 1
#define LIGHTGRAY 7
#define bioskey(a) _bios_keybrd(a)
#define gotoxy(x,y) _settextposition((short)(y), (short)(x))
#define clrscr() _clearscreen(_GWINDOW)
#define textattr(a) _settextcolor((short)((a)&0xf)); _setbkcolor((short)((a)>>4))
#define window(a,b,c,d) _settextwindow((short)(b),(short)(a),(short)(d),(short)(c))
#define cputs(s) _outtext(s)
int wherex (void);
int wherey (void);
void delay (clock_t milliseconds);
void clreol (void);
#endif
/*
//-------------------------------------
//
// Queue sizes and thresholds
//
//-------------------------------------
*/
#define TXQ 4096
#define RCVQ 4096
#define THRESH (RCVQ * 3 / 4)
/*
//-------------------------------------
//
// numbers of parameters
//
//-------------------------------------
*/
#define NUM_COM 4
#define NUM_BAUD 9
#define NUM_MODE 2
#define NUM_HND 4
/*
//-------------------------------------
//
// scan codes
//
//-------------------------------------
*/
#define A 0x1E00
#define B 0x3000
#define C 0x2E00
#define D 0x2000
#define E 0x1200
#define F 0x2100
#define G 0x2200
#define H 0x2300
#define I 0x1700
#define M 0x3200
#define N 0x3100
#define O 0x1800
#define P 0x1900
#define R 0x1300
#define S 0x1F00
#define W 0x1100
#define X 0x2D00
#define PGDN 0x5100
#define PGUP 0x4900
#define COM3A PORT2|IRQ5
/*
//-------------------------------------
//
// text attributes
//
//-------------------------------------
*/
#define NORM 0x07
#define BOLD 0x08
#define FAINT 0xF7
#ifndef BLINK
#define BLINK 0x80
#endif
#define REVRS 0x77
#define ESC 0x1b
/*
//-------------------------------------
//
// parameter constants
//
//-------------------------------------
*/
const unsigned id[] = { COM1, COM2, COM3A, COM4 };
const int baud[] = { B115200, B57600, B38400, B19200,
B9600, B4800, B2400, B1200, B300 };
const byte mode[] = { W8|S1|NONE, W7|S1|EVEN };
const byte hndshk[] = { OFF ,SOFT, HARD, HARD|SOFT };
/*
//-------------------------------------
//
// parameter indexes
//
//-------------------------------------
*/
struct indx{
byte id;
byte baud;
byte mode;
byte ansi;
byte hndshk;
byte lf;
byte echo;
}indx = { 0, 3, 0, 1, 0, 0, 0 };
/*
//-------------------------------------
//
// parameter messages
//
//-------------------------------------
*/
struct{
char *id [NUM_COM ];
char *baud [NUM_BAUD];
char *mode [NUM_MODE];
char *ansi [2];
char *hndshk[NUM_HND];
char *lf [2];
}msg={
{ "COM1", "COM2", "COM3", "COM4" },
{ "115k", "57600", "38400", "19200", "9600",
"4800", "2400", "1200", "300" },
{ "8-1-N", "7-1-E" },
{ "TTY", "ANSI" },
{ "NONE", "SOFT", "HARD", "BOTH" },
{ " ", "LF" }
};
/*
//-------------------------------------
//
// screen coordinates
//
//-------------------------------------
*/
static int x = 1; /* cursor location */
static int y = 1;
static byte attrib = NORM; /* present text attribute */
#define ERR_X 41 /* error message x coordinate */
#define STAT_X 60 /* status message x coordinate */
/*
//-------------------------------------
//
// function prototypes
//
//-------------------------------------
*/
static void Init (void);
static void Uninit (void);
static void NewParam (void);
static void Ansi (void);
static void CheckError (void);
static void CheckStatus (void);
static void Upload (void);
static void Download (void);
static int callback (int msg, unsigned param);
static void put_ch (char c);
char *Xmsg[] = { "\r\ntransfer successful",
"\r\nfile error",
"\r\ntransfer canceled",
"\r\nmemory error"
};
struct C_param param;
COM com;
/*
//-------------------------------------
//
// main()
//
//-------------------------------------
*/
void main(void)
{
char c;
unsigned key;
byte dtr = ON;
/* initialize */
Init();
while(1)
{
/* Poll the keyboard buffer for available keystrokes. */
/* Meanwhile, the receive queue is checked for available */
/* characters, check for errors and check the modem status */
while(!bioskey(1))
{
/* If a character(s) is available in the receive queue, */
/* fetch it. If it is and escape character, it must be */
/* check to see if it is the start of an ansi sequence. */
/* Otherwise the cursor position is updated, and the */
/* character is printed. */
if(ComLenRx(com))
{
c = ComGetc(com);
if(c == ESC && indx.ansi)
{
Ansi();
gotoxy(x, y);
continue;
}
put_ch(c);
}
/* Check for errors and changes in the modem status */
CheckError();
CheckStatus();
}
/* When a key is pressed, the key is fetched, and the */
/* keyboard flags are checked to see if the alt key was */
/* also pressed. If the alt key was pressed, we must */
/* check if the key is a valid command, and if so */
/* process it accordingly */
key = bioskey(0);
if(!(key & 0x00ff))
{
switch(key)
{
/* exit */
case X:
Uninit();
/* Next com port */
case C:
ComParam(com, ¶m);
ComClose(com);
do
{
indx.id++;
indx.id %= NUM_COM;
param.id = id[indx.id];
}
while((com = ComOpenS(¶m)) == NULL);
NewParam();
break;
/* Next baud rate */
case B:
indx.baud++;
indx.baud %= NUM_BAUD;
ComBaud(com, baud[indx.baud]);
NewParam();
break;
/* Next word length */
case M:
indx.mode++;
indx.mode %= NUM_MODE;
ComMode(com, mode[indx.mode]);
NewParam();
break;
/* Toggle ansi terminal */
case A:
indx.ansi ^= 1;
NewParam();
break;
/* Next handshake scheme */
case H:
indx.hndshk++;
indx.hndshk %= NUM_HND;
ComHandshake(com, hndshk[indx.hndshk], THRESH);
NewParam();
break;
/* Echo */
case E:
indx.echo ^= 1;
break;
/* Toggle LF append */
case N:
indx.lf ^= 1;
NewParam();
break;
/* Initialize hayes modem */
case I:
ComPuts(com, "ATZ\r\n");
break;
/* Hayes modem dial command */
case D:
ComPuts(com, "ATDT");
break;
/* Hayes modem hang up command */
case G:
ComPuts(com, "+++");
delay(3000);
ComPuts(com, "ATH0\r\n");
break;
case PGUP:
Upload();
break;
case PGDN:
Download();
break;
case R:
dtr ^= 1;
ComDtr(com, dtr);
break;
default:
continue;
}
}
/* If the key was not a command, put the character in the */
/* transmit queue. If the character is a carriage return, */
/* append a line feed to it just in case. */
else
{
ComPutc(com, (char)key);
if(indx.echo)
put_ch((char)key);
CheckStatus();
CheckError();
}
}
}
/*
//-------------------------------------
//
// Modified putch()
//
//-------------------------------------
*/
void put_ch(char c)
{
gotoxy(x, y);
putch(c);
if(c == '\r' && indx.lf)
putch('\n');
if(c == '\b')
printf(" \b");
x = wherex();
y = wherey();
#ifdef M_I86
if(x == 1 && y == 25)
_scrolltextwindow(1);
#endif
}
/*
//-------------------------------------
//
// Initialize
//
//-------------------------------------
*/
void Init(void)
{
FILE *fp;
/* If an initialization file exists, load it. */
fp = fopen("comdemo.ini", "rb");
if(fp)
fread(&indx, sizeof(struct indx), 1, fp);
/* Set up the screen */
clrscr();
textattr(BLUE|(LIGHTGRAY<<4));
gotoxy(1,25);
cprintf(" %4s │%5s %s │ %-4s │ %-4s │ %2s │"
" no errors │ CTS= DSR= RI= DCD= ",
msg.id[indx.id],
msg.baud[indx.baud],
msg.mode[indx.mode],
msg.ansi[indx.ansi],
msg.hndshk[indx.hndshk],
msg.lf[indx.lf]);
/* Initialize the serial port to the default parameters, */
/* set the timeout and set the DTR and RTS lines. */
com = ComOpen(id[indx.id], baud[indx.baud], mode[indx.mode], RCVQ, TXQ);
/* restore the normal screen */
textattr(LIGHTGRAY);
window(1,1,80,24);
}
/*
//-------------------------------------
//
// terminate
//
//-------------------------------------
*/
void Uninit(void)
{
FILE *fp;
/* Store the present parameters in an .ini file so the program */
/* will remember next time it is executed. */
fp = fopen("comdemo.ini", "wb");
if(fp)
fwrite(&indx, sizeof(struct indx), 1, fp);
ComClose(com);
system("cls");
puts("\n╒═════════════════════════════════════════════════════════════════════════════╕"
"\n│ Cport v2.0 - Copyright (c) 1993 Bri Productions │"
"\n├─────────────────────────────────────────────────────────────────────────────┤"
"\n│ Bri Productions, P.O. Box 7121, Fremont, CA 94537-7121, USA, (510) 794-0616 │"
"\n╘═════════════════════════════════════════════════════════════════════════════╛"
);
exit(0);
}
/*
//-------------------------------------
//
// new parameter
//
//-------------------------------------
*/
void NewParam(void)
{
/* Update the status line with the new parameters */
window(1,25, 80, 25);
textattr(BLUE|(LIGHTGRAY<<4));
cprintf(" %4s │%5s %s │ %-4s │ %-4s │ %s │",
msg.id[indx.id],
msg.baud[indx.baud],
msg.mode[indx.mode],
msg.ansi[indx.ansi],
msg.hndshk[indx.hndshk],
msg.lf[indx.lf]);
/* restore the normal screen */
textattr(attrib);
window(1,1,80,24);
gotoxy(x, y);
}
/*
//-------------------------------------
//
// ansi control sequence
//
//-------------------------------------
*/
void Ansi(void)
{
unsigned key;
char c;
char str[10];
int Pn[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int i=0,p=0;
static int oldx=1;
static int oldy=1;
/* While we are waiting for the next character, keep */
/* checking for keys. */
while((c = ComGetc(com)) == 0)
if(bioskey(1))
{
key = bioskey(0);
ComPutc(com, (char)key);
}
/* If the next character is a '[' it is probably an ansi */
/* sequence. If the next character is not a '[', print the */
/* previous escape character followed by the new character. */
if(c != '[')
{
cprintf("\x1b%c",c);
return;
}
while(1)
{
/* Read the rest of the ansi sequence, while also checking */
/* for keys. */
while((c = ComGetc(com)) == 0)
if(bioskey(1))
{
key = bioskey(0);
ComPutc(com, (char)key);
}
/* If the character is numeric, store it still it it's */
/* ascii form */
if(isdigit(c))
{
*(str+i++) = c;
continue;
}
/* When no more numeric characters are received, terminate */
/* the string and convert it to an integer, storing it in */
/* the parameter queue. */
*(str+i) = '\0';
i=0;
Pn[p++] = atoi(str);
/* Check for the ';' delimiter */
if(c == ';')
continue;
/* When no more numeric parameters are received, the */
/* command should be next. Now we can actually process */
/* the command using the stores parameters */
else
{
switch(c)
{
/* (CUP) set cursor position */
case 'H':
case 'F':
y = Pn[0] ? Pn[0] : 1;
x = Pn[1] ? Pn[1] : 1;
return;
/* (CUU) cursor up */
case 'A':
y -= Pn[0];
if(y < 1)
y = 1;
return;
/* (CUD) cursor down */
case 'B':
y += Pn[0];
if(y > 24)
y = 24;
return;
/* (CUF) cursor forward */
case 'C':
x += Pn[0];
if(x >80)
x = 80;
return;
/* (CUB) cursor backward */
case 'D':
x -= Pn[0];
if(x < 1)
x = 1;
return;
/* (SCP) save cursor position */
case 's':
oldx = x;
oldy = y;
return;
/* (RCP) restore cursor position */
case 'u':
x = oldx;
y = oldy;
return;
/* clear screen */
case 'J':
if(Pn[0] == 2)
{
clrscr();
x=1;
y=1;
}
else
{
window(1,wherey(),80,24);
clrscr();
window(1,1,80,24);
gotoxy(x, y);
}
return;
/* (EL) erase line */
case 'K':
clreol();
return;
/* An attribute command is more elaborate than the */
/* others because it may have many numeric parameters */
case 'm':
for(i=0; i<p; i++)
{
/* values from 30 to 37 define the foreground color */
if(Pn[i] >= 30 && Pn[i] <= 37)
{
attrib &= 0xf8;
attrib |= (Pn[i] - 30);
}
/* values from 40 to 47 define the background color */
if(Pn[i] >= 40 && Pn[i] <= 47)
{
attrib &= 0x8f;
attrib |= ((Pn[i] - 40) << 4);
}
/* values from 0 to 7 define the other attributes */
if(Pn[i] >= 0 && Pn[i] <= 7)
switch(Pn[i])
{
case 0:
attrib = NORM;
break;
case 1:
attrib |= BOLD;
break;
case 2:
attrib &= FAINT;
break;
case 5:
case 6:
attrib |= BLINK;
break;
case 7:
attrib ^= REVRS;
break;
default:
attrib = NORM;
}
}
/* The red and blue bits in the ansi standard are */
/* reversed relative to the IBM. Therefore, before we */
/* set the new attributes, if these bits are in */
/* opposite states toggled. This must be done for */
/* both the foreground and background. */
if((attrib & 0x05) == 0x04 || (attrib & 0x05) == 0x01)
attrib ^= 0x05;
if((attrib & 0x50) == 0x40 || (attrib & 0x50) == 0x10)
attrib ^= 0x50;
textattr(attrib);
default:
return;
}
}
}
}
/*
//-------------------------------------
//
// check for errors
//
//-------------------------------------
*/
void CheckError(void)
{
unsigned comerror;
static unsigned last_error = 0;
static int err_flg = 0;
char *errmsg[]= { { "no errors " },
{ "break detect " },
{ "frame error " },
{ "parity error " },
{ "overrun " },
{ "rx overflow " },
{ "tx overflow " }
};
comerror = ComError(com);
/* Check if the error code has changed since the last call. */
/* if it has not, there is no need to update the status line. */
/* If the error code has changed, the error conditions are */
/* checked in the order of their priority */
if(comerror != last_error)
{
last_error = comerror;
if(comerror & BREAK)
err_flg = 1;
else if(comerror & FRAMING)
err_flg = 2;
else if(comerror & PARITY)
err_flg = 3;
else if(comerror & OVERUN)
err_flg = 4;
else if(comerror & RXFULL)
err_flg = 5;
else if(comerror & TXFULL)
err_flg = 6;
else
err_flg = 0;
/* Update the status line with the new information */
window(1,25, 80, 25);
textattr(BLUE|(LIGHTGRAY<<4));
gotoxy(ERR_X,1);
cprintf(errmsg[err_flg]);
/* restore the normal screen */
textattr(attrib);
window(1,1,80,24);
gotoxy(x, y);
}
}
/*
//-------------------------------------
//
// check modem status
//
//-------------------------------------
*/
void CheckStatus(void)
{
unsigned status;
static unsigned last_status = 1;
int i;
status = ComStatus(com);
/* Check if the modem status has changed since the last call. */
/* if it has not, there is no need to update the status line. */
/* If the modem status has changed, each bit is checked for */
/* it's condition and printed on the status line */
if(status != last_status)
{
last_status = status;
window(1,25, 80, 25);
textattr(BLUE|(LIGHTGRAY<<4));
/* On each iteration, i = the x coordinate in the status */
/* line. The bits are checked for left to right. The */
/* statement !!(status & 0x10) resolves to 1 if the bit */
/* is set or 0 if the bit is clear. By adding 0x30 the */
/* 1 or 0 is converted to an ascii character */
for(i=STAT_X; i<STAT_X+6*4; i+=6)
{
gotoxy(i,1);
cprintf("%c", !!(status & 0x10) + 0x30);
status >>= 1;
}
/* restore the normal screen */
textattr(attrib);
window(1,1,80,24);
gotoxy(x, y);
}
}
/*
//-------------------------------------
//
// Upload a file
//
//-------------------------------------
*/
void Upload(void)
{
char filename[83];
int rv;
cputs("\r\n");
x = wherex();
y = wherey();
*filename = 80;
cputs("File name > ");
cgets(filename);
rv = XmodemTx(com, filename + 2, callback);
clreol();
cputs(*(Xmsg + rv));
cputs("\r\n");
x = wherex();
y = wherey();
}
/*
//-------------------------------------
//
// Download a file
//
//-------------------------------------
*/
void Download(void)
{
char filename[83];
int rv;
cputs("\r\n");
x = wherex();
y = wherey();
*filename = 80;
cputs("File name for your computer > ");
cgets(filename);
rv = XmodemRx(com, filename + 2, callback);
clreol();
cputs(*(Xmsg + rv));
cputs("\r\n");
x = wherex();
y = wherey();
}
/*
//-------------------------------------
//
// Xmodem callback function
//
//-------------------------------------
*/
int callback(int msg, XPARAM param)
{
static retry = 10;
const char *_err_txt;
static const char *err_txt[] = {
"OVER RUN",
"BAD BLOCK",
"BAD BLOCK CHECK",
"TIME OUT",
"TRANSFER CANCELED"
};
switch(msg)
{
case XM_IDLE:
break;
case XM_START:
cprintf("\r\nWaiting...");
break;
case XM_BLOCKCHECK:
cprintf("\r\nblock check:%s\r\n", param == 0 ? "CHECKSUM" : "CRC");
break;
case XM_BLOCK:
if(retry < 10)
{
retry = 10;
putchar('\n');
}
cprintf("\rblock:%d bytes: %ld", param, ((long)param) << 7);
break;
case XM_EOT:
cprintf("\r\nEOT");
break;
case XM_DONE:
break;
case XM_ERROR:
if(param & OVERUN)
_err_txt = err_txt[0];
else
_err_txt = err_txt[param >> 12];
cprintf("\r\nERROR:%s", _err_txt);
if(retry-- == 0)
return(1);
}
if(kbhit())
{
if(getch() == 0x1b)
return(1);
}
return(0);
}
/*
//-------------------------------------
//
// Microsoft portability
//
//-------------------------------------
*/
#if M_I86
int wherex(void)
{
byte rv;
_asm {
mov bh,0
mov ah,3
int 10h
inc dl
mov rv,dl
}
return(rv);
}
int wherey(void)
{
byte rv;
_asm {
mov bh,0
mov ah,3
int 10h
inc dh
mov rv,dh
}
return(rv);
}
void delay (clock_t milliseconds)
{
milliseconds += clock();
while(clock() < milliseconds);
}
void clreol(void)
{
cprintf("%*c", 80 - wherex() - 1, ' ');
}
int cprintf(const char *fmt, ...)
{
va_list list;
int rv;
char buf[129];
va_start(list, fmt);
rv = vsprintf(buf, fmt, list);
va_end(list);
_outtext(buf);
return(rv);
}
#endif